package cn.wolfcode.wolf.user.service.impl;

import cn.wolfcode.wolf.auth.config.JwtProperties;
import cn.wolfcode.wolf.core.exception.BusinessException;
import cn.wolfcode.wolf.core.utils.Md5Utils;
import cn.wolfcode.wolf.core.utils.Result;
import cn.wolfcode.wolf.redis.utils.RedisCache;

import cn.wolfcode.wolf.user.dao.UserInfoDao;
import cn.wolfcode.wolf.user.domain.UserInfo;
import cn.wolfcode.wolf.user.redis.key.UserRedisKeyPrefix;
import cn.wolfcode.wolf.user.service.UserInfoService;
import cn.wolfcode.wolf.user.vo.LoginUser;
import cn.wolfcode.wolf.user.vo.RegisterRequest;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoDao, UserInfo> implements UserInfoService {
    private final RedisCache redisCache;
    private final JwtProperties jwtProperties;

    public UserInfoServiceImpl(RedisCache redisCache, JwtProperties jwtProperties) {
        this.redisCache = redisCache;
        this.jwtProperties = jwtProperties;
    }

    @Override
    public UserInfo findByPhone(String phone) {
        //WHERE phone = #{phone}
        //return this.getOne(lambdaQuery().eq(UserInfo::getPhone, phone));
        return this.getOne(new QueryWrapper<UserInfo>().eq("phone", phone));
    }

    @Override
    public void register(RegisterRequest registerRequest) {
        //1.二次检验手机号，查询手机号是否已注册，已注册则返回异常
        UserInfo userInfo = this.findByPhone(registerRequest.getPhone());
        if(userInfo!=null){
            throw new BusinessException(Result.ERROR_REGISTER_CODE,"手机号已注册,请勿重复注册");
        }
//        Optional.ofNullable(this.findByPhone(registerRequest.getPhone())).ifPresent(userInfo -> {throw new RuntimeException("手机号已注册");});
//        2.从redis中获取验证码，校验验证码与前端传递的验证码是否一致，不正确则返回异常
        String fullKey=UserRedisKeyPrefix.USERS_REGISTER_VERIFY_CODE_STRING.fullKey(registerRequest.getPhone());
        String verifyCode = redisCache.getCacheObject(fullKey);
        //假设 registerRequest.getPhone() 返回 "12345678901"，那么构建的键将是 "USERS:REGISTER:VERIFY_CODE:12345678901"。代码会从 Redis 缓存中查找这个键对应的值，并将其赋值给 verifyCode 变量
        if(!verifyCode.equals(registerRequest.getVerifyCode())){
            throw new BusinessException(Result.ERROR_SMS_CODE,"验证码错误");
        }
//        3.将验证码从redis中删除
        redisCache.deleteObject(fullKey);
//        4.创建注册对象，存储前端传入的注册参数，设置默认头像，默认等级，默认状态
        userInfo = this.buildUserInfo(registerRequest);
//        5.对密码进行加密，设置到注册对象中
        userInfo.setPassword(Md5Utils.getMD5(userInfo.getPassword()+userInfo.getPhone()));
//        6.保存用户对象到数据库
        super.save(userInfo);

    }

    @Override
    public Map<String, Object> login(String phone, String password) {
        // 1.根据手机号查询用户对象,如果为空，则返回异常
        UserInfo userInfo = this.findByPhone(phone);
        if(userInfo==null){
            throw new BusinessException(500401,"用户不存在");
        }
        // 2.密码加密，与数据库密码进行比较，如果不一致，则返回异常
        String encryptPassword = Md5Utils.getMD5(password+userInfo.getPhone());
        if(!encryptPassword.equals(userInfo.getPassword())){
            throw new BusinessException(500401,"密码错误");
        }

        LoginUser loginUser = new LoginUser();
        BeanUtils.copyProperties(userInfo,loginUser);
        // 当前时间
        long loginTime = System.currentTimeMillis();
        loginUser.setLoginTime(loginTime);
        // 过期时间
        long expireTime = loginTime+jwtProperties.getExpireTime()* LoginUser.MINUTES_MILLISECONDS;
        loginUser.setExpireTime(expireTime);
        // 生成一个用户存入redis的key
        String uuid= UUID.randomUUID().toString().replace("-","");
        UserRedisKeyPrefix loginInfoKeyPrefix = UserRedisKeyPrefix.USERS_LOGIN_INFO_STRING;
        loginInfoKeyPrefix.setTimeout(expireTime);
        loginInfoKeyPrefix.setTimeUnit(TimeUnit.MINUTES);
        redisCache.setCacheObject(loginInfoKeyPrefix,loginUser,uuid);
        // 3.使用jwt 生成token，往token中存入用户基础信息
        Map<String,Object> payload = new HashMap<>();
        payload.put(LoginUser.LOGIN_USER_REDIS_UUID,uuid);
//        payload.put("id",userInfo.getId());
//        payload.put("nickname",userInfo.getNickname());
//        payload.put("loginTime",System.currentTimeMillis());
//        payload.put("expireTime",30);
        String jwtToken=Jwts.builder()
            .addClaims(payload)
            .signWith(SignatureAlgorithm.HS256,jwtProperties.getSecret())
            .compact();
        // 4.构建Map对象，将token以及用户对象放入map中，返回
        //userInfo.setPassword(null);使用JSONIgnore代替
        payload.clear();
        payload.put("token",jwtToken);
        payload.put("userInfo",userInfo);
        return payload;
    }

    private UserInfo buildUserInfo(RegisterRequest registerRequest){
        UserInfo userInfo = new UserInfo();
        BeanUtils.copyProperties(registerRequest,userInfo);
        userInfo.setInfo("这个人很懒，什么都没写");
        userInfo.setHeadImgUrl("/images/default.jpg");
        userInfo.setState(UserInfo.STATE_NORMAL);
        return userInfo;
    }

}
